#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
实例创建策略脚本
实现地域选择和GPU类型选择的逻辑，返回创建实例所需的参数
"""

import os
import sys
import json
import time
from typing import Dict, List, Any, Optional, Tuple
from dataclasses import dataclass
from pathlib import Path

# 添加项目根目录到Python路径
sys.path.insert(0, str(Path(__file__).parent))

# 加载环境变量
from dotenv import load_dotenv
load_dotenv()

@dataclass
class InstanceCreationParams:
    """实例创建参数"""
    region: str
    gpu_type: str
    app_id: str
    instance_name: str
    endpoint: str
    description: str
    priority_score: int
    cost_per_hour: float

class InstanceCreationStrategy:
    """实例创建策略"""
    
    def __init__(self):
        """初始化策略"""
        self.region_priority = [
            "ap-beijing",      # 北京 - app-oefac6i2
            "ap-nanjing",      # 南京 - app-9qle417n  
            "ap-guangzhou",    # 广州 - app-9diy38hx
            "ap-shanghai",     # 上海 - app-d8orpkas
            "ap-chongqing"     # 重庆 - app-h5rw7hfh
        ]
        
        self.gpu_type_priority = [
            "gpu1.2",     # 1.2元/小时配置
            "gpu2.4",     # 2.4元/小时配置（售罄）
            "gpu3.3",     # 3.3元/小时配置
            "gpu3.6",     # 3.6元/小时配置
            "gpu7.2"      # 7.2元/小时配置
        ]
        
        # 地域对应的应用ID
        self.region_apps = {
            "ap-beijing": "app-oefac6i2",
            "ap-nanjing": "app-9qle417n", 
            "ap-guangzhou": "app-9diy38hx",
            "ap-shanghai": "app-d8orpkas",
            "ap-chongqing": "app-h5rw7hfh"
        }
        
        # GPU类型成本（每小时，单位：元）- 基于实际硬件配置
        # 根据图片显示的实际定价更新
        self.gpu_costs = {
            "gpu1.2": 1.2,       # 16GB显存, 8+ TFlops SP, 8核CPU, 32GiB内存
            "gpu2.4": 2.4,       # 2*16GB显存(32GB), 16+ TFlops SP, 16核CPU, 64GiB内存 (售罄)
            "gpu3.3": 3.3,       # 24GB显存, 30+ TFlops SP, 28核CPU, 116GiB内存
            "gpu3.6": 3.6,       # 32GB显存, 15+ TFlops SP, 8~10核CPU, 40GiB内存
            "gpu7.2": 7.2        # 2*32GB显存(64GB), 30+ TFlops SP, 18~20核CPU, 80GiB内存
        }
        
        # 地域成本系数 - 实际情况下地域对成本影响很小
        self.region_cost_factors = {
            "ap-beijing": 1.0,      # 基准价格
            "ap-nanjing": 1.0,      # 地域成本差异很小
            "ap-guangzhou": 1.0,    # 主要看硬件配置
            "ap-shanghai": 1.0,     # 地域不是主要成本因素
            "ap-chongqing": 1.0     # 硬件配置决定成本
        }
    
    def get_optimal_region(self, current_instances: List[Dict] = None) -> str:
        """
        获取最优地域
        
        Args:
            current_instances: 当前实例列表
            
        Returns:
            最优地域
        """
        if not current_instances:
            current_instances = []
        
        # 统计各地域实例数量
        region_counts = {}
        for instance in current_instances:
            region = instance.get('region', '')
            region_counts[region] = region_counts.get(region, 0) + 1
        
        # 按优先级和实例数量选择
        for region in self.region_priority:
            if region not in region_counts or region_counts[region] == 0:
                return region
        
        # 如果所有地域都有实例，选择实例数量最少的
        return min(self.region_priority, key=lambda r: region_counts.get(r, 0))
    
    def get_optimal_gpu_type(self, region: str, load_level: str = "normal") -> str:
        """
        获取最优GPU类型
        
        Args:
            region: 地域
            load_level: 负载级别 (low, normal, high, critical)
            
        Returns:
            最优GPU类型
        """
        # 根据负载级别选择GPU类型
        load_gpu_mapping = {
            "low": "gpu1.2",      # 低负载使用最便宜的配置
            "normal": "gpu3.6",   # 正常负载使用基础型配置
            "high": "gpu7.2",     # 高负载使用进阶型配置
            "critical": "gpu3.3"  # 紧急负载使用高端配置
        }
        
        preferred_gpu = load_gpu_mapping.get(load_level, "gpu3.6")
        
        # 如果首选GPU类型在优先级列表中，返回它
        if preferred_gpu in self.gpu_type_priority:
            return preferred_gpu
        
        # 否则返回最便宜的
        return self.gpu_type_priority[0]
    
    def calculate_cost(self, region: str, gpu_type: str) -> float:
        """
        计算每小时成本
        
        注意：成本主要由硬件配置（GPU类型）决定，地域对成本影响很小
        
        Args:
            region: 地域（对成本影响很小）
            gpu_type: GPU类型（主要成本因素）
            
        Returns:
            每小时成本（元）
        """
        # 硬件配置是主要成本因素
        base_cost = self.gpu_costs.get(gpu_type, 3.6)
        # 地域成本系数（实际情况下差异很小）
        region_factor = self.region_cost_factors.get(region, 1.0)
        return base_cost * region_factor
    
    def get_region_priority_score(self, region: str) -> int:
        """
        获取地域优先级分数（越小越优先）
        
        Args:
            region: 地域
            
        Returns:
            优先级分数
        """
        try:
            return self.region_priority.index(region) + 1
        except ValueError:
            return 999
    
    def generate_instance_name(self, region: str, gpu_type: str) -> str:
        """
        生成实例名称
        
        Args:
            region: 地域
            gpu_type: GPU类型
            
        Returns:
            实例名称
        """
        # 获取北京时间戳（UTC+8）
        import datetime
        beijing_time = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=8)))
        beijing_timestamp = beijing_time.strftime('%Y_%m-%d_%H-%M-%S')
        
        region_short = region.replace('ap-', '')
        return f"hai-gpu-{region_short}-{gpu_type}-{beijing_timestamp}"
    
    def get_app_endpoint(self, app_id: str) -> str:
        """
        获取应用端点
        
        Args:
            app_id: 应用ID
            
        Returns:
            应用端点
        """
        return f"https://{app_id}.hai.tencentcloud.com"
    
    def create_instance_params(self, 
                             target_count: int = 1,
                             current_instances: List[Dict] = None,
                             load_level: str = "normal",
                             preferred_regions: List[str] = None) -> List[InstanceCreationParams]:
        """
        创建实例参数列表
        
        Args:
            target_count: 目标实例数量
            current_instances: 当前实例列表
            load_level: 负载级别
            preferred_regions: 优先地域列表
            
        Returns:
            实例创建参数列表
        """
        if not current_instances:
            current_instances = []
        
        if not preferred_regions:
            preferred_regions = self.region_priority.copy()
        
        params_list = []
        
        for i in range(target_count):
            # 选择最优地域
            if preferred_regions:
                # 优先从指定地域中选择
                region = self._select_region_from_preferred(preferred_regions, current_instances)
            else:
                region = self.get_optimal_region(current_instances)
            
            # 选择最优GPU类型
            gpu_type = self.get_optimal_gpu_type(region, load_level)
            
            # 获取对应的应用ID
            app_id = self.region_apps.get(region, "")
            
            # 生成实例名称
            instance_name = self.generate_instance_name(region, gpu_type)
            
            # 获取应用端点
            endpoint = self.get_app_endpoint(app_id)
            
            # 计算成本
            cost_per_hour = self.calculate_cost(region, gpu_type)
            
            # 获取优先级分数
            priority_score = self.get_region_priority_score(region)
            
            # 创建参数对象
            params = InstanceCreationParams(
                region=region,
                gpu_type=gpu_type,
                app_id=app_id,
                instance_name=instance_name,
                endpoint=endpoint,
                description=f"通过{region}地域{app_id}应用创建的{gpu_type}类型实例",
                priority_score=priority_score,
                cost_per_hour=cost_per_hour
            )
            
            params_list.append(params)
            
            # 模拟添加到当前实例列表（用于下次选择）
            current_instances.append({
                'region': region,
                'gpu_type': gpu_type,
                'instance_name': instance_name
            })
        
        return params_list
    
    def _select_region_from_preferred(self, preferred_regions: List[str], current_instances: List[Dict]) -> str:
        """
        从优先地域列表中选择地域
        
        Args:
            preferred_regions: 优先地域列表
            current_instances: 当前实例列表
            
        Returns:
            选择的地域
        """
        # 统计优先地域的实例数量
        region_counts = {}
        for instance in current_instances:
            region = instance.get('region', '')
            if region in preferred_regions:
                region_counts[region] = region_counts.get(region, 0) + 1
        
        # 按优先级顺序选择
        for region in preferred_regions:
            if region not in region_counts or region_counts[region] == 0:
                return region
        
        # 如果所有优先地域都有实例，选择实例数量最少的
        return min(preferred_regions, key=lambda r: region_counts.get(r, 0))
    
    def get_strategy_summary(self) -> Dict[str, Any]:
        """
        获取策略摘要
        
        Returns:
            策略摘要信息
        """
        return {
            "region_priority": self.region_priority,
            "gpu_type_priority": self.gpu_type_priority,
            "region_apps": self.region_apps,
            "gpu_costs": self.gpu_costs,
            "region_cost_factors": self.region_cost_factors,
            "total_regions": len(self.region_priority),
            "total_gpu_types": len(self.gpu_type_priority)
        }

def main():
    """主函数 - 演示实例创建策略"""
    print("🎯 实例创建策略演示")
    print("=" * 60)
    
    # 创建策略实例
    strategy = InstanceCreationStrategy()
    
    # 显示策略摘要
    print("\n📋 策略配置:")
    summary = strategy.get_strategy_summary()
    print(f"  可用地域: {summary['total_regions']} 个")
    print(f"  GPU类型: {summary['total_gpu_types']} 种")
    print(f"  地域优先级: {summary['region_priority']}")
    print(f"  GPU类型优先级: {summary['gpu_type_priority']}")
    
    # 显示地域应用映射
    print("\n🌍 地域应用映射:")
    for region, app_id in summary['region_apps'].items():
        print(f"  {region}: {app_id}")
    
    # 显示成本信息
    print("\n💰 成本信息:")
    print("  GPU类型成本 (元/小时):")
    for gpu_type, cost in summary['gpu_costs'].items():
        print(f"    {gpu_type}: {cost}")
    
    print("  地域成本系数:")
    for region, factor in summary['region_cost_factors'].items():
        print(f"    {region}: {factor}")
    
    # 演示不同场景的实例创建
    scenarios = [
        {"name": "扩容到3个实例", "target_count": 3, "load_level": "normal"},
        {"name": "高负载扩容", "target_count": 2, "load_level": "high"},
        {"name": "优先选择北京和南京", "target_count": 2, "preferred_regions": ["ap-beijing", "ap-nanjing"]},
        {"name": "紧急扩容", "target_count": 1, "load_level": "critical"}
    ]
    
    for scenario in scenarios:
        print(f"\n🚀 场景: {scenario['name']}")
        print("-" * 40)
        
        # 创建实例参数
        params_list = strategy.create_instance_params(
            target_count=scenario['target_count'],
            load_level=scenario.get('load_level', 'normal'),
            preferred_regions=scenario.get('preferred_regions')
        )
        
        # 显示结果
        for i, params in enumerate(params_list, 1):
            print(f"  实例 {i}:")
            print(f"    地域: {params.region}")
            print(f"    GPU类型: {params.gpu_type}")
            print(f"    应用ID: {params.app_id}")
            print(f"    实例名称: {params.instance_name}")
            print(f"    端点: {params.endpoint}")
            print(f"    成本: {params.cost_per_hour:.2f} 元/小时")
            print(f"    优先级分数: {params.priority_score}")
            print()
    
    # 生成JSON格式的创建参数
    print("📄 JSON格式的创建参数:")
    print("-" * 40)
    
    # 创建5个实例的参数
    params_list = strategy.create_instance_params(target_count=5, load_level="normal")
    
    # 转换为JSON格式
    json_params = []
    for params in params_list:
        json_params.append({
            "region": params.region,
            "gpu_type": params.gpu_type,
            "app_id": params.app_id,
            "instance_name": params.instance_name,
            "endpoint": params.endpoint,
            "description": params.description,
            "priority_score": params.priority_score,
            "cost_per_hour": params.cost_per_hour
        })
    
    print(json.dumps(json_params, indent=2, ensure_ascii=False))

if __name__ == "__main__":
    main()
